<template>
  <view class="ui-fixed">
    <view
      :id="`fixed-${uuid}`"
      class="ui-fixed-box"
      :class="[{ fixed: state.fixed }]"
      :style="[
        {
          left: sticky ? 'auto' : '0px',
          top: state.fixed && !bottom ? (noNav ? val : val + sys_navBar) + 'px' : 'auto',
          bottom: insetHeight,
          zIndex: index + sheep.$zIndex.navbar,
        },
        !alway ? { opacity: state.opacityVal } : '',
      ]"
    >
      <view class="ui-fixed-content" :style="[{ zIndex: index + sheep.$zIndex.navbar }]" @tap="toTop">
        <slot></slot>
        <view
          v-if="safeAreaInsets.bottom && bottom && isInset"
          class="inset-bottom"
          :style="[{ height: safeAreaInsets.bottom + 'px' }]"
        ></view>
      </view>
      <view v-if="bottom" class="ui-fixed-bottom" :class="[bg]"></view>
      <view
        class="ui-fixed-bg"
        :class="[ui, bg]"
        :style="[{ zIndex: index + sheep.$zIndex.navbar - 1 }, bgStyles, opacity ? { opacity: state.opacityVal } : '']"
      ></view>
    </view>
    <view
      v-if="sticky ? state.fixed : placeholder && state.fixed"
      class="skeleton"
      :style="[{ height: state.content.height + 'px', width: width + 'px' }]"
    ></view>
  </view>
</template>

<script setup>
import { onPageScroll } from '@dcloudio/uni-app'
import { getCurrentInstance, unref, onMounted, reactive, nextTick, computed } from 'vue'
import sheep from '@/sheep'
const { safeAreaInsets } = sheep.$platform.device

const vm = getCurrentInstance()

const uuid = sheep.$helper.guid()
const sys_navBar = sheep.$platform.navbar
const state = reactive({
  content: {},
  fixed: true,
  scrollTop: 0,
  opacityVal: 0,
})
const insetHeight = computed(() => {
  if (state.fixed && props.bottom) {
    if (props.isInset) {
      return props.val + 'px'
    } else {
      return props.val + safeAreaInsets.bottom + 'px'
    }
  } else {
    return 'auto'
  }
})
const props = defineProps({
  noNav: {
    type: Boolean,
    default: false,
  },
  bottom: {
    type: Boolean,
    default: false,
  },
  bg: {
    type: String,
    default: '',
  },
  bgStyles: {
    type: Object,
    default() {},
  },
  val: {
    type: Number,
    default: 0,
  },
  width: {
    type: [String, Number],
    default: 0,
  },
  alway: {
    type: Boolean,
    default: true,
  },
  opacity: {
    type: Boolean,
    default: false,
  },
  index: {
    type: [Number, String],
    default: 0,
  },
  placeholder: {
    type: [Boolean],
    default: false,
  },
  sticky: {
    type: [Boolean],
    default: false,
  },
  noFixed: {
    type: Boolean,
    default: false,
  },
  ui: {
    type: String,
    default: '',
  },
  clickTo: {
    type: Boolean,
    default: false,
  },
  //是否需要安全区
  isInset: {
    type: Boolean,
    default: true,
  },
})

state.fixed = !unref(props.sticky)
onPageScroll((e) => {
  let top = e.scrollTop
  state.scrollTop = top
  state.opacityVal = top > sheep.$platform.navbar ? 1 : top * 0.01
})

onMounted(() => {
  nextTick(() => {
    computedQuery()
  })
})

const computedQuery = () => {
  uni
    .createSelectorQuery()
    .in(vm)
    .select(`#fixed-${uuid}`)
    .boundingClientRect((data) => {
      if (data != null) {
        state.content = data
        if (unref(props.sticky)) {
          setFixed(state.scrollTop)
        }
      }
    })
    .exec()
}

const setFixed = (value) => {
  if (unref(props.bottom)) {
    state.fixed =
      value >= state.content.bottom - sheep.$platform.device.windowHeight + state.content.height + unref(props.val)
  } else {
    state.fixed =
      value >= state.content.top - (unref(props.noNav) ? unref(props.val) : unref(props.val) + sheep.$platform.navbar)
  }
}

const toTop = () => {
  if (props.hasToTop) {
    uni.pageScrollTo({
      scrollTop: state.content.top,
      duration: 100,
    })
  }
}
</script>

<style lang="scss">
.ui-fixed {
  .ui-fixed-box {
    position: relative;
    width: 100%;
    &.fixed {
      position: fixed;
    }
    .ui-fixed-content {
      position: relative;
    }
    .ui-fixed-bg {
      position: absolute;
      width: 100%;
      height: 100%;
      top: 0;
      z-index: 1;
      pointer-events: none;
    }
  }
}
.inset-bottom {
  background: #fff;
}
</style>
